#pragma once

#include "BaseInc.h"

class UI_API CArgument
{
public :
	CArgument()
		:m_bHandled(false), m_iRetVal(0)
	~CArgument();

	bool GetHandled() const { return m_bHandled;}
	void SetHandled(bool bHandled) { m_bHandled = bHandled;}

	int_x GetRetVal() const { return m_iRetVal;}
	void SetRetVal(int_x retVal) { m_iRetVal = retVal;}

private :
	bool m_bHandled;
	int_x m_iRetVal;
};

const uint_x EVENT_FLAG_ACTIVE = 0x00000001;
template<typename ArgsType>
class UI_API IEventHandle
{
public :
	virtual void Handle(CArgument & args) = 0;
};

template<typename ArgsType, typename HandleType>
class UI_API CEventModel
{
private :
	class HandleData
	{
	public:
		HandleData() : pHandle(nullptr), flags(0) {}
		HandleData(HandleType * pEventHandle, uint_x dataFlags) : pHandle(pEventHandle), flags(dataFlags) {}
		HandleType * pHandle;
		uint_x flags;
	};

public :
	CEventModel()
		: m_handles(true)
	{
	}
	void operator()(ArgsType & args)
	{
		ListTmpl<HandleData>::Iterator begin = m_handles.Begin();
		ListTmpl<HandleData>::Iterator end = m_handles.End();
		while(begin != end)
		{
			if((*begin).flags & EVENT_FLAG_ACTIVE)
				(*begin).pHandle->Handle(args);
			++begin;
		}
		m_handles.RemoveBy(
			[&](const HandleData & data)->bool
			{
				return !(data.flags & EVENT_FLAG_ACTIVE);
			}
		);
	}

	bool IsListening(const HandleType * pHandle)
	{
		ListTmpl<HandleData>::Iterator begin = m_handles.Begin();
		ListTmpl<HandleData>::Iterator end = m_handles.End();
		while(begin != end)
		{
			if((*begin).pHandle == pHandle)
			{
				return true;
			}
			++begin;
		}
		return false;
	}
	bool IsListening(const HandleType & handle)
	{
		return IsListening(&handle);
	}

	VOID RemoveAllListener()
	{
		m_handles.RemoveAll();
	}

	CEventModel & operator = (HandleType * pHandle)
	{
		m_handles.Destroy();
		m_handles.Add(HandleData(pHandle, EVENT_FLAG_ACTIVE));
		return *this;
	}
	CEventModel & operator += (HandleType * pHandle)
	{
		if(!IsListening(pHandle))
			m_handles.Add(HandleData(pHandle, EVENT_FLAG_ACTIVE));
		else { }
		return *this;
	}
	CEventModel & operator += (HandleType & handle)
	{
		return operator+=(&handle);
	}
	CEventModel & operator -= (HandleType * pHandle)
	{
		ListTmpl<HandleData>::Iterator begin = m_handles.Begin();
		ListTmpl<HandleData>::Iterator end = m_handles.End();
		while(begin != end)
		{
			if((*begin).pHandle == pHandle)
			{
				(*begin).flags &= ~EVENT_FLAG_ACTIVE;
				break;
			}
			++begin;
		}
		return *this;
	}
protected:
	ListTmpl<HandleData> m_handles;
};


